using System;
using System.Collections.Generic;
using UnityEngine;

namespace Gj
{
    public class LogService : GameService
    {
        public static LogService single;
        private Dictionary<string, List<Notice>> noticeDic;

        private Dictionary<string, float> store;

        static LogService()
        {
            single = new LogService();
        }

        public void OnDestroy()
        {
            single = new LogService();
        }

        public void OnInit()
        {
            store = new Dictionary<string, float>();
            noticeDic = new Dictionary<string, List<Notice>>();
        }

        public void OnUpdate()
        {
            
        }

        public void OnChange(byte type, byte category, Action<float> action)
        {
            OnChange(GetKey(type, category), new Notice { notice = action });
        }

        public void OnChange(byte type, Action<byte, float> action)
        {
            OnChange(GetKey(type), new Notice { cateNotice = action });
        }

        private void OnChange(string key, Notice n)
        {
            if (!noticeDic.ContainsKey(key)) noticeDic.Add(key, new List<Notice>());
            noticeDic[key].Add(n);
        }

        public void Record(GameObject player, GameObject target, byte type, byte category, float value)
        {
            Debug.LogFormat("{0} -> {1}: {2} {3} {4}", player.name, target.name, type, category, value);
            SaveLog(type, category, value);
        }

        public void Event(GameObject player, byte type, byte category, float value)
        {
            Debug.LogFormat("{0}: {1} {2} {3}", player.name, type, category, value);
            SaveLog(type, category, value);
        }

        private void SaveLog(byte type, byte category, float value)
        {
            SaveLog(GetKey(type), value);
            SaveLog(GetKey(type, category), value);

            Broadcast(type, category, value);
        }

        private void SaveLog(string key, float value)
        {
            if (!store.ContainsKey(key))
                store.Add(key, value);
            else
                store[key] = store[key] + value;
        }

        private List<Notice> GetNoticList(string key)
        {
            if (noticeDic.ContainsKey(key))
                return noticeDic[key];
            return null;
        }

        private void Broadcast(byte type, byte category, float value)
        {
            var noticList = GetNoticList(GetKey(type));
            if (noticList != null)
                foreach (var n in noticList)
                    if (n.cateNotice != null)
                        n.cateNotice(category, value);
                    else
                        noticList.Remove(n);
            if (category != 0)
            {
                noticList = GetNoticList(GetKey(type, category));
                if (noticList != null)
                    foreach (var n in noticList)
                        if (n.notice != null)
                            n.notice(value);
                        else
                            noticList.Remove(n);
            }
        }

        public float LoadLog(byte type, byte category)
        {
            if (type != 0 && category != 0)
                return LoadLog(GetKey(type, category));
            return 0;
        }

        public float LoadLog(byte type)
        {
            return LoadLog(GetKey(type));
        }

        public float LoadLog(string key)
        {
            if (store.ContainsKey(key))
                return store[key];
            return 0;
        }

        private string GetKey(byte type)
        {
            return type + "*";
        }

        private string GetKey(byte type, byte category)
        {
            return type + "-" + category;
        }

        private struct Notice
        {
            public Action<float> notice;
            public Action<byte, float> cateNotice;
        }
    }
}